<template>
  <div class="edit-form-h5-box">
    <Form
      @submit="submit"
      :colon="colon"
      ref="form"
      @failed="onFailed"
      :show-error-message="showErrorMessage"
      :labelWidth="labelWidth"
    >
      <div v-if="linkingHandle(o)" v-for="(o, i) in infos" :key="i">
        <slot name="up" :info="o"></slot>
        <Cell v-if="o.upTips" :border="false">{{o.upTips}}</Cell>
        <components
          :ref="`ref${o.key}`"
          :is="`${o.type || 'input'}-item`"
          v-model="o.value"
          :info="o"
          :border="border"
          @change="updateParam"
          @update="update"
        >
          <slot :name="o.key" :info="o"></slot>
        </components>
        <slot name="down" :info="o"></slot>
      </div>
      <div class="oprate-box" v-if="showSubmit">
        <Button round block type="info" size="normal" native-type="submit">{{submitText}}</Button>
      </div>
    </Form>
  </div>
</template>

<script>
/**
 * 1、Field内的value和v-model 除了checkbox是Array类型外 其余都是String类型
 * 2、布局：Form > Field + Button
 * 3、生命周期：created - mounted - created nextTick - mounted nextTick（微任务） - setTimeout（宏任务）
 */
import { Cell, CellGroup, Form, Field, Button, Toast } from 'vant'
import components from './register'
import { infos } from './mock'
export default {
  name: 'EditForm',
  components: {
    Cell,
    CellGroup,
    Form,
    Field,
    Button,
    Toast,
    ...components
  },
  data () {
    // created处理param的时机有点晚，此时数据已经初始化完成了。除非使用深拷贝赋值，使param相关节点重新渲染
    const setParam = v => {
      let param = {}
      v.map(o => {
        param[o.key] = o.value
      })
      return param
    }
    return {
      // 处理表单参数（此处为了表单联动做的数据更新）
      param: setParam(this.infos)
    }
  },
  props: {
    infos: {
      type: Array,
      default: () => infos
    },
    // 默认 90 或者 '90px'
    labelWidth: {
      type: [Number, String],
      default: () => 90
    },
    // 显示表单项错误信息
    showErrorMessage: {
      type: Boolean,
      default: false
    },
    // 显示提交按钮
    showSubmit: {
      type: Boolean,
      default: true
    },
    submitText: {
      type: String,
      default: '提交'
    },
    // 子项所有label带冒号
    colon: {
      type: Boolean,
      default: true
    },
    // 子项所有border
    border: {
      type: Boolean,
      default: true
    }
  },
  methods: {
    // 暴露一个可以主动触发提交表单的方法
    onSubmit () {
      this.$refs.form.submit()
    },
    submit (v) {
      // 表单展示类型为view时，param重置为原始值，而非显示值
      this.infos.map(o => {
        if (o.showType === 'view') {
          v[o.key] = o.value
        }
      })
      delete v.undefined
      // 抛出提交内容
      console.log(v)
      this.$emit('submit', v)
    },
    onFailed (v) {
      // 吐司提示校验未通过的表单项
      console.log(v)
      let { message } = v.errors[0]
      Toast({
        duration: 1000,
        message
      })
    },
    linkingHandle (o) {
      // 表单联动项的显隐和是否禁用（linking: [{},{}] 或 {}）
      if (o.linking) {
        if (Array.isArray(o.linking)) {
          return o.linking.every(e => this.linkingFn(e))
        } else {
          return this.linkingFn(o)
        }
      }
      return true
    },
    linkingFn (o) {
      // 表单联动项的显隐和是否禁用
      let { key, value, linkingType } = o.linking || o
      let linkedValue = this.param[key]
      if (linkingType === 'hidden') {
        let hidden = Array.isArray(linkedValue)
          ? linkedValue.includes(value)
          : linkedValue === value
        return !hidden
      }
      if (linkingType === 'show') {
        let show = Array.isArray(linkedValue)
          ? linkedValue.includes(value)
          : linkedValue === value
        return show
      }
      if (linkingType === 'disabled') {
        let disabled = Array.isArray(linkedValue)
          ? linkedValue.includes(value)
          : linkedValue === value
        o.disabled = disabled
      }
      if (linkingType === 'undisabled') {
        let disabled = Array.isArray(linkedValue)
          ? linkedValue.includes(value)
          : linkedValue === value
        o.disabled = !disabled
      }
      return true
    },
    // 处理表单参数（此处为了表单联动做的数据更新）
    updateParam (v, key, label) {
      this.param[key] = v
      // 暴露表单参数
      this.$emit('updateParam', this.param, key, v, label)
      console.log(key, v)
    },
    // 暴露一个可以修改子项的数据的方法
    setValue (key, v) {
      let e = this.$refs[`ref${key}`]
      e && e[0] && e[0].setValue(v)
    },
    // 出发loading，表示状态更新中
    update (v) {
      this.$emit('update', v)
    }
  }
}
</script>

<style lang="postcss" scoped>
.edit-form-h5-box .oprate-box {
  padding: 25px 16px;
}
</style>
